#include "Precompiled.hpp"
#include "output.hpp"
ostream& operator<<(ostream& os, const IMAGE_OPTIONAL_HEADER32& opt_header)
{
    const IMAGE_OPTIONAL_HEADER32* p_opt_header = &opt_header;
    os << "--------------------------------IMAGE_OPTIONAL_HEADER-----------------" << endl;
    os << "Linker version: " << dec << p_opt_header->MajorLinkerVersion << "." << dec <<p_opt_header->MinorLinkerVersion << endl;
    os << "EnteryPoint:    " << hex << "0x" << p_opt_header->AddressOfEntryPoint << endl;
    os << "ImageBase:      " << hex << "0x" << p_opt_header->ImageBase << endl;
    os << "SectionAlignment: " << hex << "0x" << p_opt_header->SectionAlignment << endl;
    os << "FileAlignment:    " << hex << "0x" << p_opt_header->FileAlignment << endl;
    os << "Subsystem:        " << hex << "0x" << p_opt_header->Subsystem << endl;
    
    os << "NumberOfRvaAndSizes:                 " << hex << "0x" << p_opt_header->NumberOfRvaAndSizes << endl;
    os << "\t IMAGE_NUMBEROF_DIRECTORY_ENTRIES: " << hex << "0x" << IMAGE_NUMBEROF_DIRECTORY_ENTRIES << endl;
    int num_rva_size = p_opt_header->NumberOfRvaAndSizes < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ?
        p_opt_header->NumberOfRvaAndSizes: IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
    for ( int i = 0; i < num_rva_size; ++i){
        if (p_opt_header->DataDirectory[i].VirtualAddress != 0 ||
            p_opt_header->DataDirectory[i].Size != 0){
            os << i << ": (" << hex << "0x" << p_opt_header->DataDirectory[i].VirtualAddress << ", "
               << hex << "0x" << p_opt_header->DataDirectory[i].Size << ")" << endl;
        }
    }
    os << "_____________________________________________________________________" << endl;
    return os;
}
ostream& operator<<(ostream& os, const IMAGE_FILE_HEADER& file_header)
{
    os << "----------------------------------IMAGE_FILE_HEADER----------------" << endl;
    const IMAGE_FILE_HEADER* p_file_header = &file_header;    
    os << "Machine              = " << hex << "0x" << p_file_header->Machine << endl
       << "NumOfSections        = " << hex << "0x" << p_file_header->NumberOfSections << endl
       << "TimeDateStamp        = " << hex << "0x" << p_file_header->TimeDateStamp << endl
       << "PointerToSymbolTable = " << hex << "0x" << p_file_header->PointerToSymbolTable << endl
       << "SizeOfOptionalHeader = " << hex << "0x" << p_file_header->SizeOfOptionalHeader << endl;
    os << "___________________________________________________________________" << endl;
    return os;
}
ostream& operator<<(ostream& os, const IMAGE_SECTION_HEADER& sec_header)
{
    os << "--------------------------------IMAGE_SECTION_HEADER-----------------" << endl;
    os << "Sec Name    = " << sec_header.Name << endl
       << "\tVirtualAddress      = " << hex << "0x" << sec_header.VirtualAddress << endl
       << "\tSize                = " << hex << "0x" << sec_header.Misc.VirtualSize << endl
       << "\tPointerToRawData    = " << hex << "0x" << sec_header.PointerToRawData << endl
       << "\tSizeOfRawData       = " << hex << "0x" << sec_header.SizeOfRawData << endl;
    os << "_______________________________________________________________________" << endl << endl;
    return os;
}


void print_ied(const IMAGE_EXPORT_DIRECTORY* p_dir, int file_offset, int virtual_addr, int size, int delta_k)
{
    const char* p_data = reinterpret_cast<const char*>(p_dir);
    
    cout << "--------------------------IMAGE_EXPORT_DIRECTORY---------------------" << endl;
    cout << "Characteristics   = " << hex << "0x" << p_dir->Characteristics << endl;
    cout << "TimeDateStamp     = " << hex << "0x" << p_dir->TimeDateStamp << endl;
    cout << "NumberOfFunctions = " << hex << "0x" << p_dir->NumberOfFunctions << endl;
    cout << "NumberOfNames     = " << hex << "0x" << p_dir->NumberOfNames << endl;

    int name_raw_offset = p_dir->Name + delta_k;
    const char* name = p_data +  name_raw_offset - file_offset;

    cout << "Name offset       = " << p_dir->Name << " [" << name<< "]" << " raw offset: " << name_raw_offset <<  endl;
    
    cout << "Base               = " << p_dir->Base << endl;
    cout << "AddressOfNames     = " << p_dir->AddressOfNames << endl;
    cout << "AddressOfFunctions = " << hex << "0x" << p_dir->AddressOfFunctions << endl;

    int address_of_functions_file_offset = p_dir->AddressOfFunctions + delta_k;
    const DWORD* function_addr = reinterpret_cast<const DWORD*>(p_data + address_of_functions_file_offset - file_offset);
    const char* name_addr = p_data + p_dir->AddressOfNames - file_offset;

    cout << "Ordinal " <<"\t RVA" << "\t Offset" << "\t Name" << endl;
        
    for (int i = 0; i < p_dir->NumberOfFunctions; ++i){
        int ordinal = p_dir->Base + i;
        cout << p_dir->Base + i <<  hex << "\t0x" << function_addr[i] << "\t0x" << function_addr[i] + delta_k;
        int address_of_name_ordinals_file_offset = p_dir->AddressOfNameOrdinals + delta_k;
        const WORD* ordinals = reinterpret_cast<const WORD*>(p_data + address_of_name_ordinals_file_offset - file_offset);
        
        int address_of_names_file_offset = p_dir->AddressOfNames + delta_k;
        const DWORD* p_names = reinterpret_cast<const DWORD*> (p_data + address_of_names_file_offset - file_offset) ;

        for( int j = 0; j < p_dir->NumberOfNames; ++j){
            if (ordinals[j] == ordinal - p_dir->Base){
                int address_of_name_file_offset = *(p_names + j) + delta_k;
                const char* name = p_data + address_of_name_file_offset - file_offset;
                cout << "\t" << name ;
            }
        }

        if( function_addr[i] > virtual_addr && function_addr[i] < virtual_addr + size ){
            cout << "  -->> " ;
            int forward_file_offset = function_addr[i] + delta_k;
            const char* forward_name = p_data + forward_file_offset - file_offset;
            cout << " " << forward_name;            
        }

        cout << endl;
    }
    cout << "_______________________________________________________________" << endl << endl;

    
}
